package  
{
//	import flash.utils.*;
	import flash.system.System;
	import flash.net.URLRequest;
	
	import flash.display.*;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	
	import zephyr.cameracontrol.FreeCamera3DController;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.events.MouseEvent;
	import org.papervision3d.cameras.FreeCamera3D;
	import org.papervision3d.objects.primitives.Cube;
	import org.papervision3d.objects.primitives.Plane;
	import org.papervision3d.objects.primitives.Sphere;
	import org.papervision3d.render.BasicRenderEngine;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.view.Viewport3D;
	import org.papervision3d.events.InteractiveScene3DEvent;
	import org.papervision3d.objects.DisplayObject3D;
	
	import org.papervision3d.materials.MovieMaterial;
	import org.papervision3d.materials.ColorMaterial;
	import org.papervision3d.materials.BitmapFileMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.core.proto.MaterialObject3D;
	import org.papervision3d.core.math.Number3D;
	
	import gs.TweenFilterLite;
	import gs.TweenLite;
	//import caurina.transitions.Equations;
	import zephyr.transitions.None;
	import zephyr.transitions.Quad;
	import zephyr.transitions.Cubic;
	import zephyr.transitions.Quart;
	import zephyr.transitions.Quint;
	import zephyr.transitions.Sine;
	import zephyr.transitions.Circ;
	import zephyr.transitions.Expo;
	import zephyr.transitions.Elastic;
	import zephyr.transitions.Back;
	import zephyr.transitions.Bounce;
	
	import flash.filters.DropShadowFilter;
	import flash.geom.Rectangle;
	
	import flash.ui.Keyboard;
	import flash.events.KeyboardEvent;
	
	import zephyr.utils.FPS;

	public class FlashPano extends Sprite
	{
	
	public var viewport:Viewport3D;
	public var scene:Scene3D;
	public var camera:FreeCamera3D;
	
	public var renderer:BasicRenderEngine;
	
	private var fc3d:FreeCamera3DController;
	
	public var frontclip:Sprite	= new Sprite();
	public var backclip:Sprite	= new Sprite();
	public var leftclip:Sprite	= new Sprite();
	public var rightclip:Sprite	= new Sprite();
	public var upclip:Sprite	= new Sprite();
	public var downclip:Sprite	= new Sprite();
	
	public var panoCubeTree:Array = [ 
										{ name: "front", 	mc: frontclip, 	url: "images/Concert_1-sm_f.jpg" },
										{ name: "back", 	mc: backclip, 	url: "images/Concert_1-sm_b.jpg" }, 
										{ name: "left",	 	mc: leftclip, 	url: "images/Concert_1-sm_l.jpg" }, 
										{ name: "right", 	mc: rightclip, 	url: "images/Concert_1-sm_r.jpg" }, 
										{ name: "top", 		mc: upclip, 	url: "images/Concert_1-sm_u.jpg" }, 
										{ name: "bottom", 	mc: downclip, 	url: "images/Concert_1-sm_d.jpg" } 
									];
										
	private var panoCubeReservedName:String = "__panoCube";
	
	// materialList object for the pano textured cube
	public var materials:MaterialsList = new MaterialsList();;
	
	// count var to keep track of the number of image that have loaded so that a transition will have simultaneously across all cube faces
	private var panoImageloadCount:int = 0;
	
	private var initialColor:uint = 0x000000;
	
	private var meterTree:Sprite = new Sprite();
	//count var to keep track of how many meter items need to load before proceeding to load everything else
	private var meterTreeLoadCount:int = 0;
	//holds the bytesLoaded and bytesTotal for the loader
	private var meterLoadingStats:Array = new Array();
	
	// object that will have registered as its methods all of the directives for 2D elements the need to update position on resize.
	private var resizeTree:Object = new Object();
	
	private var whatToDoWith3dSpots:String = "delete_all";
	private var childrenOfScene:Object = new Object();
	private var exceptional3dSpots:Array = new Array();
	
	private var tooltip:Sprite = new Sprite();
	private var tooltipTexts:Object = new Object();
	private var tooltip_text:String = "...";
	
	private var slider:Sprite = new Sprite();
	private var sliderContent:Sprite = new Sprite();
	private var gap:Number = 5;
	private var contentRect:Rectangle;
	private var rect:Rectangle;
	private var init2dObjectsCalled:Boolean = false;
	
	private var navStrip:Sprite = new Sprite();
	
	private var hideShow:TextField = new TextField();
	
	public var viewportInterface:Viewport3D;
	public var sceneInterface:Scene3D;
	public var cameraInterface:FreeCamera3D;
	
	public var frontsprite:Sprite	= new Sprite();
		public var backsprite:Sprite	= new Sprite();
		public var leftsprite:Sprite	= new Sprite();
		public var rightsprite:Sprite	= new Sprite();
		public var upsprite:Sprite		= new Sprite();
		public var downsprite:Sprite	= new Sprite();
		public var thumbCubeTree:Array = [ 
										{ name: "front", 	mc: frontsprite },
										{ name: "back", 	mc: backsprite }, 
										{ name: "left",	 	mc: leftsprite }, 
										{ name: "right", 	mc: rightsprite }, 
										{ name: "top", 		mc: upsprite }, 
										{ name: "bottom", 	mc: downsprite } 
									];
										
		private var thumbCubeReservedName:String = "__thumbCube";
		private var thumbCube:Cube;
		private var thumbCubeMaterials:MaterialsList;
	
		public function FlashPano() 
		{	
			//set up the stage
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.frameRate = 30;
			stage.quality = StageQuality.MEDIUM;
			
// 			cursor = new upCursor();
// 			addChild(cursor);
// 			Mouse.hide();
			
			// call init to start building everything!
			directory("initMeter");
		}
		
		private function directory(goTo:String=null):void
		{	
			if (goTo == "initMeter")
				initMeter();
			
			// called by meterTreeCompleteHandler when meter images finish loading
			else if (goTo == "init3dSpace")
			{
				initPapervision();
				
				initPanoCube();
				
				initFirstScene();
				
			}
			//called by loaderCompleteHandler when load is done
			else if (goTo == "initRenderLoop")
				initRenderLoop();
			
			// Called by afterTransition, and only to be called ONCE
			else if (goTo == "init2dObjects")
			{
				if ( !(init2dObjectsCalled) )
				{
					init2dObjectsCalled = true;
					init2dObjects();
				}
			}
		}
		
		private function initMeter():void
		{	
			var bgL:Loader = new Loader();
			bgL.name = "background";
			bgL.load( new URLRequest("graphics/meter/background.png") );
			bgL.contentLoaderInfo.addEventListener(Event.COMPLETE, meterTreeCompleteHandler, false, 0, true);
			meterTree.addChild( bgL );
			
			var lL:Loader = new Loader();
			lL.name = "line";
			lL.load( new URLRequest("graphics/meter/line.png") );
			lL.contentLoaderInfo.addEventListener(Event.COMPLETE, meterTreeCompleteHandler, false, 0, true);
			meterTree.addChild( lL );
			
		}
		
		private function meterTreeCompleteHandler(e:Event):void
		{
			if (meterTreeLoadCount < 1) { meterTreeLoadCount++; }
			else
			{	
				// register all three images' positioning directives with the resizeTree so position will update onResize
				resizeTree.background = function():void {
					meterTree.getChildByName("background").x 	= stage.stageWidth/2 - meterTree.getChildByName("background").width/2;
					meterTree.getChildByName("background").y 	= stage.stageHeight/2 - meterTree.getChildByName("background").height/2;
				};
				resizeTree.background();
				
				resizeTree.line = function():void {
					meterTree.getChildByName("line").x 	= stage.stageWidth/2 - meterTree.getChildByName("line").width/2;
					meterTree.getChildByName("line").y 	= stage.stageHeight/2 - meterTree.getChildByName("line").height/2 + 35;
				};
				resizeTree.line();
				
				// set line scale to 0 to reflect 0% loaded.
				meterTree.getChildByName("line").scaleX	= 0;
				
// 				var t:TextField = new TextField();
//  				t.text = "start";				
// 				meterTree.addChild( t );
				
				addChild(meterTree);
				
				directory("init3dSpace");

			}
		}
		
		private function initPapervision():void
		{
			//Viewport3D(viewportWidth:Number = 640, viewportHeight:Number = 480, autoScaleToStage:Boolean = false, interactive:Boolean = false, autoClipping:Boolean = true, autoCulling:Boolean = true)
			viewport = new Viewport3D( 800, 600, true, true);
			addChildAt( viewport, 0 );
			
			scene = new Scene3D();

			camera = new FreeCamera3D();
			
			camera.zoom = 10;
			
			//default camera z is -1000, need to set it to 0
			camera.z = 0;
			
			renderer = new BasicRenderEngine();
			
			//camera controller, needs scene, camera, and viewport.
			fc3d = new FreeCamera3DController( this, false  );
			fc3d.sensitivity = 60;
			fc3d.friction = 0.3;
			fc3d.autoRotateIncrement = 15;
		}
		
		
		private function initPanoCube():void
		{	
			var quality :Number = 28;
						
			//materials = new MaterialsList();
			
			for each(  var o:Object in panoCubeTree )
			{
				o.mc.name = o.name;
				
				o.mc.graphics.beginFill( initialColor );
				o.mc.graphics.drawRect( 0, 0, 150, 150 );
				o.mc.graphics.endFill();
				
				//MovieMaterial( movieAsset:DisplayObject=null, transparent:Boolean=false, animated:Boolean=false, precise:Boolean = false )
				var movieMaterial:MovieMaterial = new MovieMaterial( o.mc, false, false, false );
				movieMaterial.interactive = false;
				movieMaterial.oneSide = true;
				movieMaterial.smooth = true;
				movieMaterial.precise = false;
				
				materials.addMaterial( movieMaterial, o.name );
			}
			var insideFaces  :int = Cube.ALL;
			var excludeFaces :int = Cube.NONE;
			var cube:Cube = new Cube( materials, 100000, 100000, 100000, quality, quality, quality, insideFaces, excludeFaces );
			
			scene.addChild( cube, panoCubeReservedName );
			
			var fpsz:FPS = new FPS();
			addChild(fpsz);
		}
		
		private function init2dObjects():void
		{	
			
			// Cheathamlane
			var cheatham:TextField = new TextField();
			cheatham.name = "cheatham";
			cheatham.selectable = false;
			cheatham.cacheAsBitmap = true;
			cheatham.autoSize = TextFieldAutoSize.LEFT;			
			var cheathamFormat:TextFormat = new TextFormat();
			cheathamFormat.font = "Verdana";
			cheathamFormat.color = 0xFFFFFF;
			cheathamFormat.size = 12;
			cheatham.defaultTextFormat = cheathamFormat;
			cheatham.text = "Photography by: Patrick Cheatham";
			navStrip.addChild(cheatham);
			// register the position function with resizeTree
			resizeTree.cheatham = function():void { 
				navStrip.getChildByName("cheatham").x = 20; 
				navStrip.getChildByName("cheatham").y = stage.stageHeight - 137; 
				};
			resizeTree.cheatham();
			
			
			// navStrip Container
			
			navStrip.name = "navStrip";
			navStrip.buttonMode = true;
			this.addChild(navStrip);
			
			
			//bottom background
			
			var background:Loader = new Loader();
			background.name = "background";
			background.load( new URLRequest("graphics/bg.png") );
			background.contentLoaderInfo.addEventListener(Event.COMPLETE, navLoadComplete);
			navStrip.addChildAt(background,0);
			resizeTree.background = function():void 
			{
			navStrip.getChildByName("background").x = 0;
			navStrip.getChildByName("background").y = stage.stageHeight - 140;
			navStrip.getChildByName("background").scaleX = stage.stageWidth;
			}
			resizeTree.background();
			
			// hide / show button
			var hideShowSprite:Sprite = new Sprite();
			hideShowSprite.name = "hideShowSprite";
			hideShowSprite.mouseChildren = false;
			hideShowSprite.addEventListener(MouseEvent.MOUSE_DOWN, hideClick, false, 0, true);
			hideShowSprite.addEventListener(MouseEvent.MOUSE_OVER, hideOver, false, 0, true);
			hideShowSprite.addEventListener(MouseEvent.MOUSE_OUT, hideOut, false, 0, true);
			
			hideShow.name = "hideShow";
			hideShow.selectable = false;
			hideShow.cacheAsBitmap = true;
			hideShow.autoSize = TextFieldAutoSize.LEFT;			
			var hideShowFormat:TextFormat = new TextFormat();
			hideShowFormat.font = "Verdana";
			hideShowFormat.color = 0xFFFFFF;
			hideShowFormat.size = 14;
			hideShow.defaultTextFormat = hideShowFormat;
			hideShow.text = "Hide Navigation";
			hideShowSprite.addChild(hideShow);
			navStrip.addChild(hideShowSprite);
			// register the position function with resizeTree
			resizeTree.hideShow = function():void { 
				navStrip.getChildByName("hideShowSprite").x = stage.stageWidth - 200; 
				navStrip.getChildByName("hideShowSprite").y = stage.stageHeight - 138; 
				};
			resizeTree.hideShow();
			
			
			//CONTROL BUTTONS IN THE NAV STRIP
			var autorotation:Loader = new Loader();
			autorotation.name = "autorotation";
			autorotation.load( new URLRequest("graphics/rotate_normal.png") );
			autorotation.contentLoaderInfo.addEventListener(Event.COMPLETE, navLoadComplete);
			navStrip.addChild(autorotation);
			resizeTree.autorotation = function():void { 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("autorotation").x = stage.stageWidth - 254; 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("autorotation").y = stage.stageHeight - 47; 
				};
			resizeTree.autorotation();
			autorotation.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			autorotation.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			autorotation.addEventListener(MouseEvent.MOUSE_DOWN, autorotationClick, false, 0, true);
			autorotation.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			autorotation.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.autorotation = "Start/Stop Auto Rotation";
			
			
			var zoomOut:Loader = new Loader();
			zoomOut.name = "zoomOut";
			zoomOut.load( new URLRequest("graphics/zoomout_normal.png") );
			zoomOut.contentLoaderInfo.addEventListener(Event.COMPLETE, navLoadComplete);
			navStrip.addChild(zoomOut);
			resizeTree.zoomOut = function():void { 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("zoomOut").x = stage.stageWidth - 219; 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("zoomOut").y = stage.stageHeight - 47; 
				};
			resizeTree.zoomOut();
			zoomOut.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			zoomOut.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			zoomOut.addEventListener(MouseEvent.MOUSE_DOWN, zoomOutClick, false, 0, true);
			zoomOut.addEventListener(MouseEvent.MOUSE_UP, zoomOutRelease, false, 0, true);
			zoomOut.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			zoomOut.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.zoomOut = "Zoom Out";
			
			
			var zoomIn:Loader = new Loader();
			zoomIn.name = "zoomIn";
			zoomIn.load( new URLRequest("graphics/zoomin_normal.png") );
			zoomIn.contentLoaderInfo.addEventListener(Event.COMPLETE, navLoadComplete);
			navStrip.addChild(zoomIn);
			resizeTree.zoomIn = function():void { 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("zoomIn").x = stage.stageWidth - 185; 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("zoomIn").y = stage.stageHeight - 47; 
				};
			resizeTree.zoomIn();
			zoomIn.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			zoomIn.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			zoomIn.addEventListener(MouseEvent.MOUSE_DOWN, zoomInClick, false, 0, true);
			zoomIn.addEventListener(MouseEvent.MOUSE_UP, zoomInRelease, false, 0, true);
			zoomIn.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			zoomIn.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.zoomIn = "Zoom In";
			
			
			var panLeft:Loader = new Loader();
			panLeft.name = "panLeft";
			panLeft.load( new URLRequest("graphics/panleft_normal.png") );
			panLeft.contentLoaderInfo.addEventListener(Event.COMPLETE, navLoadComplete);
			navStrip.addChild(panLeft);
			resizeTree.panLeft = function():void { 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("panLeft").x = stage.stageWidth - 151; 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("panLeft").y = stage.stageHeight - 47; 
				};
			resizeTree.panLeft();
			panLeft.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			panLeft.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			panLeft.addEventListener(MouseEvent.MOUSE_DOWN, panLeftClick, false, 0, true);
			panLeft.addEventListener(MouseEvent.MOUSE_UP, panLeftRelease, false, 0, true);
			panLeft.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			panLeft.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.panLeft = "Pan Left";
			
			
			var panRight:Loader = new Loader();
			panRight.name = "panRight";
			panRight.load( new URLRequest("graphics/panright_normal.png") );
			panRight.contentLoaderInfo.addEventListener(Event.COMPLETE, navLoadComplete);
			navStrip.addChild(panRight);
			resizeTree.panRight = function():void { 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("panRight").x = stage.stageWidth - 117; 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("panRight").y = stage.stageHeight - 47; 
				};
			resizeTree.panRight();
			panRight.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			panRight.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			panRight.addEventListener(MouseEvent.MOUSE_DOWN, panRightClick, false, 0, true);
			panRight.addEventListener(MouseEvent.MOUSE_UP, panRightRelease, false, 0, true);
			panRight.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			panRight.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.panRight = "Pan Right";
			
			
			var tiltUp:Loader = new Loader();
			tiltUp.name = "tiltUp";
			tiltUp.load( new URLRequest("graphics/tiltup_normal.png") );
			tiltUp.contentLoaderInfo.addEventListener(Event.COMPLETE, navLoadComplete);
			navStrip.addChild(tiltUp);
			resizeTree.tiltUp = function():void { 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("tiltUp").x = stage.stageWidth - 83; 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("tiltUp").y = stage.stageHeight - 47; 
				};
			resizeTree.tiltUp();
			tiltUp.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			tiltUp.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			tiltUp.addEventListener(MouseEvent.MOUSE_DOWN, tiltUpClick, false, 0, true);
			tiltUp.addEventListener(MouseEvent.MOUSE_UP, tiltUpRelease, false, 0, true);
			tiltUp.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			tiltUp.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.tiltUp = "Tilt Up";
			
			
			var tiltDown:Loader = new Loader();
			tiltDown.name = "tiltDown";
			tiltDown.load( new URLRequest("graphics/tiltdown_normal.png") );
			tiltDown.contentLoaderInfo.addEventListener(Event.COMPLETE, navLoadComplete);
			navStrip.addChild(tiltDown);
			resizeTree.tiltDown = function():void { 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("tiltDown").x = stage.stageWidth - 49; 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("tiltDown").y = stage.stageHeight - 47; 
				};
			resizeTree.tiltDown();
			tiltDown.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			tiltDown.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			tiltDown.addEventListener(MouseEvent.MOUSE_DOWN, tiltDownClick, false, 0, true);
			tiltDown.addEventListener(MouseEvent.MOUSE_UP, tiltDownRelease, false, 0, true);
			tiltDown.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			tiltDown.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.tiltDown = "Tilt Down";
			
			
			var buttonFullScreen:Loader = new Loader();
			buttonFullScreen.name = "buttonFullScreen";
			buttonFullScreen.load( new URLRequest("graphics/button_fullscreen.png") );
			buttonFullScreen.contentLoaderInfo.addEventListener(Event.COMPLETE, navLoadComplete);
			navStrip.addChild(buttonFullScreen);
			resizeTree.buttonFullScreen = function():void { 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("buttonFullScreen").x = stage.stageWidth - 64; 
				DisplayObjectContainer(getChildByName("navStrip")).getChildByName("buttonFullScreen").y = stage.stageHeight - 90; 
				};
			resizeTree.buttonFullScreen();
			buttonFullScreen.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			buttonFullScreen.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			buttonFullScreen.addEventListener(MouseEvent.CLICK, buttonFullScreenClick, false, 0, true);
			buttonFullScreen.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			buttonFullScreen.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.buttonFullScreen = "Fullscreen";
			
			
			/// TOOLTIP
			
			var tooltipSprite:Sprite = new Sprite();
			tooltipSprite.name = "tooltipBackground";
			
			var tooltipBackground:Shape = new Shape();
			tooltipBackground.graphics.beginFill(0xFFFFFF,0.8);
			tooltipBackground.graphics.drawRoundRect(0,0,140,30,10,10);
			tooltipBackground.graphics.moveTo(15,30);
			tooltipBackground.graphics.lineTo(60,40);
			tooltipBackground.graphics.lineTo(30,30);
			tooltipBackground.graphics.endFill();
			tooltipSprite.addChild(tooltipBackground)
			tooltipSprite.scale9Grid  = new Rectangle(10,10,119,10);
			
			
			var shadow:DropShadowFilter = new DropShadowFilter();
			shadow.distance = 10;
			shadow.angle = 45;
			shadow.alpha = 0.75;
			tooltipSprite.filters = [shadow];
			
			var tooltipText:TextField = new TextField();
			
			tooltip.addChild(tooltipSprite);
			tooltip.addChild(tooltipText);
			//addChild(tooltip);
			
			tooltipText.x = 5;
			tooltipText.y = 5;
			//tooltipSprite.addChild(tooltipText);
			
			tooltipText.name = "tooltipTextField";
			tooltipText.autoSize = TextFieldAutoSize.LEFT;
			
			var tooltipTextFormat:TextFormat = new TextFormat();
			tooltipTextFormat.font = "Verdana";
			tooltipTextFormat.color = 0x444444;
			tooltipTextFormat.size = 12;
			tooltipText.defaultTextFormat = tooltipTextFormat;
			
			tooltipTexts.none = "...";
			tooltipText.htmlText = tooltipTexts.none;
			tooltipSprite.width = tooltipText.width+10;
			tooltipSprite.height = tooltipText.height+25;
			
			
			/*
			///THUMBNAIL SLIDER.  JUST UNCOMMENT TO USE.
			slider.name = "slider";
			navStrip.addChild(slider);
			//slider.buttonMode = true;
			
			slider.addChild(sliderContent);
			
			sliderContent.name = "sliderContent";
			sliderContent.x = 37;
			sliderContent.y = -10;
			
			resizeTree.slider = function():void { 
				slider.x = 25; 
				slider.y = stage.stageHeight - 100;
				var rectangleWidth:Number = stage.stageWidth * 0.5;
				//(getChildByName("cheatham") as TextField).text = String(rectangleWidth);
				var rectangle:Rectangle = sliderContent.scrollRect || new Rectangle(0,0,rectangleWidth,100);
				// set it again so that if it already existed it will be re-calculated
				rectangle.width = rectangleWidth;
				sliderContent.scrollRect = rectangle;
				slider.getChildByName("rightArrow").x = slider.getChildByName("leftArrow").width + rectangle.width + 10;
				};
			
			
			
			var leftArrow:Loader = new Loader();
			leftArrow.name = "leftArrow";
			leftArrow.load( new URLRequest("graphics/panleft_normal.png") );
			leftArrow.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void { resizeTree.slider(); }, false, 0, true);
			leftArrow.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			leftArrow.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			leftArrow.addEventListener(MouseEvent.MOUSE_DOWN, sliderLeftClick, false, 0, true);
			leftArrow.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			leftArrow.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.leftArrow = "Previous Scenes";
			leftArrow.x = 0;
			leftArrow.y = 33;
			slider.addChild(leftArrow);
			
			
			var rightArrow:Loader = new Loader();
			rightArrow.name = "rightArrow";
			rightArrow.load( new URLRequest("graphics/panright_normal.png") );
			rightArrow.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			rightArrow.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			rightArrow.addEventListener(MouseEvent.MOUSE_DOWN, sliderRightClick, false, 0, true);
			rightArrow.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			rightArrow.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.rightArrow = "Next Scenes";
			//rightArrow.x = 347;
			rightArrow.y = 33;
			slider.addChild(rightArrow);
			
			/// layout slider, arrows, etc....
			resizeTree.slider();
			
			var t1:Loader = new Loader();
			t1.name = "t1";
			t1.load( new URLRequest("graphics/concert1.jpg") );
			t1.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			t1.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			t1.contentLoaderInfo.addEventListener(Event.COMPLETE, sliderContentItemLoaded, false, 0, true);
			t1.addEventListener(MouseEvent.MOUSE_DOWN, initFirstScene, false, 0, true);
			t1.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			t1.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.t1 = "Primary View";
			sliderContent.addChild(t1);
			
			var t2:Loader = new Loader();
			t2.name = "t2";
			t2.load( new URLRequest("graphics/concert2.jpg") );
			t2.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			t2.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			t2.contentLoaderInfo.addEventListener(Event.COMPLETE, sliderContentItemLoaded, false, 0, true);
			t2.addEventListener(MouseEvent.MOUSE_DOWN, initConcert2, false, 0, true);
			t2.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			t2.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.t2 = "Alternate View";
			sliderContent.addChild(t2);
			
			var t3:Loader = new Loader();
			t3.name = "t3";
			t3.load( new URLRequest("graphics/concert1.jpg") );
			t3.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			t3.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			t3.contentLoaderInfo.addEventListener(Event.COMPLETE, sliderContentItemLoaded, false, 0, true);
			t3.addEventListener(MouseEvent.MOUSE_DOWN, initFirstScene, false, 0, true);
			t3.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			t3.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.t3 = "Primary View";
			sliderContent.addChild(t3);
			
			var t4:Loader = new Loader();
			t4.name = "t4";
			t4.load( new URLRequest("graphics/concert2.jpg") );
			t4.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			t4.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			t4.contentLoaderInfo.addEventListener(Event.COMPLETE, sliderContentItemLoaded, false, 0, true);
			t4.addEventListener(MouseEvent.MOUSE_DOWN, initConcert2, false, 0, true);
			t4.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			t4.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.t4 = "Alternate View";
			sliderContent.addChild(t4);
			
			var t5:Loader = new Loader();
			t5.name = "t5";
			t5.load( new URLRequest("graphics/concert1.jpg") );
			t5.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			t5.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			t5.contentLoaderInfo.addEventListener(Event.COMPLETE, sliderContentItemLoaded, false, 0, true);
			t5.addEventListener(MouseEvent.MOUSE_DOWN, initFirstScene, false, 0, true);
			t5.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			t5.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.t5 = "Primary View";
			sliderContent.addChild(t5);
			
			var t6:Loader = new Loader();
			t6.name = "t6";
			t6.load( new URLRequest("graphics/concert2.jpg") );
			t6.addEventListener(MouseEvent.MOUSE_OVER, navOver, false, 0, true);
			t6.addEventListener(MouseEvent.MOUSE_OUT, navOut, false, 0, true);
			t6.contentLoaderInfo.addEventListener(Event.COMPLETE, sliderContentItemLoaded, false, 0, true);
			t6.addEventListener(MouseEvent.MOUSE_DOWN, initConcert2, false, 0, true);
			t6.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			t6.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			tooltipTexts.t6 = "Alternate View";
			sliderContent.addChild(t6);
			*/
			
			TweenLite.delayedCall(0.1, init3dInterface);
		}
		
		private function navLoadComplete(event:Event):void 
		{ 
			var theTweenTime:Number = 4*(Math.random());
			TweenLite.from(event.target.loader, theTweenTime, {alpha:0, ease:Bounce.easeInBounce});	
		}
		
		private function init3dInterface():void
		{
			viewportInterface = new Viewport3D( 125, 125, false, true);
			//viewportInterface.name="viewportInterface";
			navStrip.addChild( viewportInterface );
			resizeTree.viewportInterface = function():void {
				viewportInterface.x = 67; 
				viewportInterface.y = stage.stageHeight - 125; 
				};
			resizeTree.viewportInterface();
			
			sceneInterface = new Scene3D();

			cameraInterface = new FreeCamera3D();
			
			//cameraInterface.zoom = 10;
			
			//default camera z is -1000, need to set it to 0
			cameraInterface.z = -150;
			
			initThumbCube();
			
			viewportInterface.addEventListener( Event.ENTER_FRAME, interfaceOnEnterFrame );
		}
		
		private function initThumbCube():void
		{
			var quality :Number = 2;
						
			thumbCubeMaterials = new MaterialsList();
			
			for each(  var o:Object in thumbCubeTree )
			{
				o.mc.name = o.name;
				
				o.mc.graphics.beginFill( initialColor );
				o.mc.graphics.drawRect( 0, 0, 100, 100 );
				o.mc.graphics.endFill();
				
				//MovieMaterial( movieAsset:DisplayObject=null, transparent:Boolean=false, animated:Boolean=false, precise:Boolean = false )
				var movieMaterial:MovieMaterial = new MovieMaterial( o.mc );
				movieMaterial.interactive = true;
				movieMaterial.oneSide = true;
				movieMaterial.smooth = true;
				
				
				thumbCubeMaterials.addMaterial( movieMaterial, o.name );
			}
			var insideFaces  :int = Cube.NONE;
			var excludeFaces :int = Cube.NONE;
			//var excludeFaces :int = Cube.TOP+Cube.BOTTOM;
			thumbCube = new Cube( thumbCubeMaterials, 100, 100, 100, quality, quality, quality, insideFaces, excludeFaces );
			
			sceneInterface.addChild( thumbCube, thumbCubeReservedName );
			
			thumbCubeTree[0].url = "graphics/concert1.jpg";
			thumbCubeTree[1].url = "graphics/concert1.jpg";
			thumbCubeTree[2].url = "graphics/concert2.jpg";
			thumbCubeTree[3].url = "graphics/concert2.jpg";
			thumbCubeTree[4].url = "graphics/concert1.jpg";
			thumbCubeTree[5].url = "graphics/concert2.jpg";
			
			thumbCubeTree[0].action = initFirstScene;
			thumbCubeTree[1].action = initFirstScene;
			thumbCubeTree[2].action = initConcert2;
			thumbCubeTree[3].action = initConcert2;
			thumbCubeTree[4].action = initFirstScene;
			thumbCubeTree[5].action = initConcert2;
			
			thumbCubeTree[0].tooltip = "Primary View";
			thumbCubeTree[1].tooltip = "Primary View";
			thumbCubeTree[2].tooltip = "Alternate View";
			thumbCubeTree[3].tooltip = "Alternate View";
			thumbCubeTree[4].tooltip = "Primary View";
			thumbCubeTree[5].tooltip = "Alternate View";
			
			for each( o in thumbCubeTree )
			{
				// load images
				var req:URLRequest = new URLRequest(o.url);
				var loader:Loader = new Loader();
				loader.name = o.name;
				loader.load( req );
				
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbCubeCompleteHandler, false, 0, true);
				loader.addEventListener(MouseEvent.MOUSE_DOWN, thumbCubeDownHandler, false, 0, true);
				loader.addEventListener(MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
				loader.addEventListener(MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
				tooltipTexts[loader.name] = o.tooltip;
			}
		}
		
		private function thumbCubeCompleteHandler(e:Event):void 
		{ 
			for each(  var o:Object in thumbCubeTree )
			{
			if ( e.target.loader.name == o.name ) 
				{
				
				// rotate the top texture 180 degree due to "feature" in Cube.as that lays it out wrong
				if (o.name == "top")
				{
					e.target.loader.x = e.target.loader.width;
					e.target.loader.y = e.target.loader.width;
					e.target.loader.rotation = 180;
				}
				// get reference to the current face material
				var mo3d:MaterialObject3D = thumbCubeMaterials.getMaterialByName(o.name);
				
				// switch animated on so material updates
				(mo3d as MovieMaterial).animated = true;
				
				o.mc.addChild(e.target.loader);
				
				// scale the image underneath to the same size as the new one for the transition
				if (o.mc.numChildren > 1) 
				{
					var underneathImage:DisplayObject = o.mc.getChildAt(o.mc.numChildren-2);
					
					//set the scale of the underneath image to the scale of the new top image so the two are the same size
					var underneathImageScaleX:Number = e.target.loader.width / underneathImage.width;
					var underneathImageScaleY:Number = e.target.loader.height / underneathImage.height;
					underneathImage.scaleX = underneathImageScaleX;
					underneathImage.scaleY = underneathImageScaleY;
					
					//top image always must be at (x,y) = (e.target.loader.width, e.target.loader.height) due to "feature" in Cube.as that lays it out spun 180 deg.
					if (o.name == "top")
					{
						underneathImage.x = underneathImage.width;
						underneathImage.y = underneathImage.height;
					}
				}
				
				// tween material and switch off for better performance
				TweenLite.from( (e.target.loader as DisplayObject), 1, {alpha:0.1, onComplete:turnOffAnimationOnThumbCube } );
				//TweenLite.delayedCall(1, turnOffAnimationOnThumbCube);
				}
			}
		}
		
		private var thumbImageloadCount:int = 0;
		
		private function turnOffAnimationOnThumbCube():void
		{
			if (thumbImageloadCount < 5) { thumbImageloadCount++; }
			else
			{ 
				//re-set loadCount
				panoImageloadCount = 0;
				
				for each(  var o:Object in thumbCubeTree )
				{
					//get reference to mo3d
					var mo3d:MaterialObject3D = thumbCubeMaterials.getMaterialByName(o.name);
					//much better performance with animation off
					(mo3d as MovieMaterial).animated = false;
				}
			}
		}
		
		public function interfaceOnEnterFrame(e:Event):void
		{
			thumbCube.yaw(0.5);
			renderer.renderScene( sceneInterface, cameraInterface, viewportInterface );
		}
		
		private function thumbCubeDownHandler(event:Event):void
		{
			for each(  var o:Object in thumbCubeTree )
			{
				if ( event.currentTarget.name == o.name )
				{
					o.action();
				}
			}
		}
		
		
		private function initFirstScene(e:Event=null):void
		{	
			// what to do with old hotspots
			deleteAll();
			
			// create a plane hotspot
			var pmat:BitmapFileMaterial = new BitmapFileMaterial( "graphics/hotspot.png" );
			pmat.oneSide = false;
			pmat.interactive = true;
			pmat.smooth = true;
			//Plane( material:MaterialObject3D=null, width:Number=0, height:Number=0, segmentsW:Number=0, segmentsH:Number=0, initObject:Object=null )
			var toConcert2:Plane = new Plane(pmat, 1772, 1772, 2, 2, pinToSphere(40000,-10,-8) );
			toConcert2.lookAt(camera as DisplayObject3D);
			toConcert2.addEventListener( InteractiveScene3DEvent.OBJECT_CLICK, initConcert2, false, 0, true );
			scene.addChild( toConcert2, "toConcert2" );
			toConcert2.addEventListener( MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true );
			toConcert2.addEventListener( MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true );
			toConcert2.addEventListener( MouseEvent.MOUSE_OVER, buttonModeOn, false, 0, true );
			toConcert2.addEventListener( MouseEvent.MOUSE_OUT, buttonModeOff, false, 0, true );
			tooltipTexts[toConcert2.name] = "Alternate View";
			
			panoCubeTree[0].url = "images/Concert_1-sm_f.jpg";
			panoCubeTree[1].url = "images/Concert_1-sm_b.jpg";
			panoCubeTree[2].url = "images/Concert_1-sm_l.jpg";
			panoCubeTree[3].url = "images/Concert_1-sm_r.jpg";
			panoCubeTree[4].url = "images/Concert_1-sm_u.jpg";
			panoCubeTree[5].url = "images/Concert_1-sm_d.jpg";
			
			for each(  var o:Object in panoCubeTree )
			{
				// load images
				var req:URLRequest = new URLRequest(o.url);
				var loader:Loader = new Loader();
				loader.name = o.name;
				loader.load( req );
				loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, imageLoadProgressHandler, false, 0, true);
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler, false, 0, true);
			}
			
		}
		
		// Adds enter_frame handler to re-render 3D scene on each frame, and resize
		private function initRenderLoop():void
		{
			//addEventListener( Event.ENTER_FRAME, onEnterFrame );
			stage.addEventListener( Event.RESIZE, onResize );
			
		}
		
		private function onEnterFrame( e:Event=null ):void
		{
			renderer.renderScene( scene, camera, viewport );
			
			//autorotate
// 			if (fc3d != null)
// 				fc3d.targetRotationY = camera.rotationY + 0.1;
			
			///DEBUGGING
//			trace ( System.totalMemory );
		}
		
		private function onResize(e:Event=null):void
		{	
			// all 2D objects that need to be re-positioned on resizing register their .x and .y directives as
			// anonymous functions in the resizeTree obj and the resize handler loops through and executes the functions.
			for (var f:String in resizeTree)
			{
				resizeTree[f]();
			}
			
			renderer.renderScene( scene, camera, viewport );
		}
		
		private function initConcert2( e:Event=null):void 
		{	
			//delete all old hotspots except... (if they exist);
			deleteAll();
			
			meterTree.visible = true;
			TweenLite.to(meterTree, 1, {autoAlpha:1} );
//			Tweener.addTween(meterTree, {alpha:1, time:2, transition:"linear" });
			
			panoCubeTree[0].url = "images/Concert_2_blend-flat-s_f.jpg";
			panoCubeTree[1].url = "images/Concert_2_blend-flat-s_b.jpg";
			panoCubeTree[2].url = "images/Concert_2_blend-flat-s_l.jpg";
			panoCubeTree[3].url = "images/Concert_2_blend-flat-s_r.jpg";
			panoCubeTree[4].url = "images/Concert_2_blend-flat-s_u.jpg";
			panoCubeTree[5].url = "images/Concert_2_blend-flat-s_d.jpg";
			
			for each(  var o:Object in panoCubeTree )
			{	
				var req:URLRequest = new URLRequest(o.url);
				var loader:Loader = new Loader();
				loader.name = o.name;
				loader.load( req );
				loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, imageLoadProgressHandler, false, 0, true);
				loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler, false, 0, true);
			}
			
			// create a plane hotspot
			var pmat:BitmapFileMaterial = new BitmapFileMaterial( "graphics/hotspot.png" );
			pmat.oneSide = false;
			pmat.interactive = true;
			pmat.smooth = true;
			
			//Plane( material:MaterialObject3D=null, width:Number=0, height:Number=0, segmentsW:Number=0, segmentsH:Number=0, initObject:Object=null )
			var toConcert1:Plane = new Plane(pmat, 1772, 1772, 2, 2, pinToSphere(40000,80,5) );
			toConcert1.lookAt(camera as DisplayObject3D);
			toConcert1.addEventListener( InteractiveScene3DEvent.OBJECT_CLICK, initFirstScene, false, 0, true );
			toConcert1.addEventListener( MouseEvent.MOUSE_OVER, tooltipOn, false, 0, true);
			toConcert1.addEventListener( MouseEvent.MOUSE_OUT, tooltipOff, false, 0, true);
			toConcert1.addEventListener( MouseEvent.MOUSE_OVER, buttonModeOn, false, 0, true );
			toConcert1.addEventListener( MouseEvent.MOUSE_OUT, buttonModeOff, false, 0, true );
			tooltipTexts[toConcert1.name] = "Primary View";
			
			scene.addChild( toConcert1, "toConcert1" );
		}
		
		
		private function imageLoadProgressHandler(e:Event):void
		{
			var li:LoaderInfo = LoaderInfo(e.target);
						
			var cumulativeBytesLoaded:int = 0;
			var cumulativeBytesTotal:int = 0;
			
			// if this is the first call of this function add in the first item
			if (meterLoadingStats.length == 0)
			{ 
				meterLoadingStats.push( {bytesLoaded:li.bytesLoaded, bytesTotal:li.bytesTotal} );
			}
			
			// loop through looking for the same loader based on same bytesTotal and less loaded than the target loader 
			// and add the bytes all up for use
			for each(  var o:Object in meterLoadingStats )
			{
				// adding bytes
				cumulativeBytesLoaded += o.bytesLoaded;
				cumulativeBytesTotal += o.bytesTotal;
				//checking if same loader
				if (o.bytesTotal == li.bytesTotal && o.bytesLoaded < li.bytesLoaded)
				{
					//adding in the difference between last stored amount and the target amount
					var diffInBytes:int = li.bytesLoaded - o.bytesLoaded;
					cumulativeBytesLoaded += diffInBytes;
					o.bytesLoaded = li.bytesLoaded;
					var found:Boolean = true;
				}
			}
			// if this is a new loader, then add it.
			if (!found)
			{
				meterLoadingStats.push( {bytesLoaded:li.bytesLoaded, bytesTotal:li.bytesTotal} );
				cumulativeBytesLoaded += li.bytesLoaded;
				cumulativeBytesTotal += li.bytesTotal;
			}
			// set meter based on cumulative totals
			meterTree.getChildByName("line").scaleX = cumulativeBytesLoaded / cumulativeBytesTotal;
			
			// if cumulative load is done!: fade meter out
			if (cumulativeBytesLoaded / cumulativeBytesTotal == 1)
			{	
				TweenLite.to(meterTree, 1, { autoAlpha:0 } );
				
			}
		}
		
		// panoCube's load complete handler
		private function loaderCompleteHandler(e:Event):void 
		{
		//call directory -> start render loop
		directory("initRenderLoop");
				
		for each(  var o:Object in panoCubeTree )
			{
			if ( e.target.loader.name == o.name ) 
				{
				
				// rotate the top texture 180 degree due to "feature" in Cube.as that lays it out wrong
				if (o.name == "top")
				{
					e.target.loader.x = e.target.loader.width;
					e.target.loader.y = e.target.loader.width;
					e.target.loader.rotation = 180;
				}
				// get reference to the current face material
				var mo3d:MaterialObject3D = materials.getMaterialByName(o.name);
				
				// switch animated on so material updates
				(mo3d as MovieMaterial).animated = true;
				// switch off smooth, for better transition performance
				(mo3d as MovieMaterial).smooth = false;
				
				e.target.loader.alpha=0.1;
				o.mc.addChild(e.target.loader);
				
				// scale the image underneath to the same size as the new one for the transition
				if (o.mc.numChildren > 1) 
				{
					var underneathImage:DisplayObject = o.mc.getChildAt(o.mc.numChildren-2);
					
					//set the scale of the underneath image to the scale of the new top image so the two are the same size
					var underneathImageScaleX:Number = e.target.loader.width / underneathImage.width;
					var underneathImageScaleY:Number = e.target.loader.height / underneathImage.height;
					underneathImage.scaleX = underneathImageScaleX;
					underneathImage.scaleY = underneathImageScaleY;
					
					//top image always must be at (x,y) = (e.target.loader.width, e.target.loader.height) due to "feature" in Cube.as that lays it out spun 180 deg.
					if (o.name == "top")
					{
						underneathImage.x = underneathImage.width;
						underneathImage.y = underneathImage.height;
					}
				}
				
				// tween material and switch off for better performance
				TweenLite.to( (e.target.loader as DisplayObject), 2, {alpha:1, onComplete:afterTransition, onUpdate:onEnterFrame } );
				//Tweener.addTween(e.target.loader, {alpha:1.25, time:5, transition:"linear", onComplete:function ():void { afterTransition(); } });
				saveOrDelete3dSpotsOnTransition();
				}
			}
		}
		
		// afterTransition removes the old underneath images in the material mc's 
		private function afterTransition():void 
		{	
			//Wait until the sixth call so all 6 faces have faded in.
			if (panoImageloadCount < 5) { panoImageloadCount++ }
			else
			{ 
				//re-set loadCount
				panoImageloadCount = 0;
				
				//clear meterLoadingStats for the next load
				meterLoadingStats = [];
				
				for each(  var o:Object in panoCubeTree )
				{
					//get reference to mo3d
					//var mo3d:MaterialObject3D = materials.getMaterialByName(o.name);
					//much better performance with animation off
					//(mo3d as MovieMaterial).animated = false;
						
					//clear out invisible loaders on lower on the display list
					while ( o.mc.numChildren > 1 )
					{ 	
						// get reference to bottom-most object
						var objToDestroy:DisplayObject = o.mc.getChildAt(0); 
						//remove it
						o.mc.removeChildAt(0);
						// if it is a Loader unload it
						if ( objToDestroy is Loader) 
						{
							(objToDestroy as Loader).unload();
						}
						// nullify it
						objToDestroy = null;
					}
				}
				// turn off animation.  Animation does not seem to complete always if turned of inside this function
				// turn on smoothing again, which was off for the transition
				//TweenLite.delayedCall(delay:Number, onComplete:Function, onCompleteParams:Array=null);
				TweenLite.delayedCall(0.1, turnOffAnimationOnPanoCube);
				
				// delay call until pano has come in not to overload the pano transition frames.
				directory("init2dObjects");
				
				fc3d.autoRotation = true;
			}
		}	
		
		private function turnOffAnimationOnPanoCube():void
		{
			for each(  var o:Object in panoCubeTree )
			{
				//get reference to mo3d
				var mo3d:MaterialObject3D = materials.getMaterialByName(o.name);
				//much better performance with animation off
				(mo3d as MovieMaterial).animated = false;
				//turn back on smoothing (which was off during the transition
				(mo3d as MovieMaterial).smooth = true;
			}
		}
		
		/* hotspot organization between nodes.  ONLY for 3D hotspots, 2D hotspots are assumed to stay across all nodes
		the default is saveAll with no exceptions.  to delete all call deleteAll
		If there are exceptions use saveAllExcept() or deleteAllExcept() and pass in an array of the exceptional hotspot names 
		(names are set when calling scene.addChild(variable_name, "string_name") )
		*/
		private function saveAll():void
		{
			whatToDoWith3dSpots = "saveAll";
			this.exceptional3dSpots = [];
		}
		private function deleteAll():void
		{
			whatToDoWith3dSpots = "deleteAll";
			childrenOfScene = {};
			for (var i:String in scene.children)
				childrenOfScene[i] = scene.children[i]; 
			this.exceptional3dSpots = [];
		}
		private function saveAllExcept(exceptional3dSpots:Array = null):void
		{
			whatToDoWith3dSpots = "saveAll";
			childrenOfScene = {};
			for (var i:String in scene.children)
				childrenOfScene[i] = scene.children[i];
			if ( exceptional3dSpots == null )
				this.exceptional3dSpots = [];
			else
				this.exceptional3dSpots = exceptional3dSpots;
		}
		private function deleteAllExcept(exceptional3dSpots:Array = null):void
		{
			whatToDoWith3dSpots = "deleteAll";
			childrenOfScene = {};
			for (var i:String in scene.children)
				childrenOfScene[i] = scene.children[i];
			if ( exceptional3dSpots == null )
				this.exceptional3dSpots = [];
			else
				this.exceptional3dSpots = exceptional3dSpots;
		}
		
		
		private function saveOrDelete3dSpotsOnTransition():void
		{	
			if ( whatToDoWith3dSpots == "saveAll" )
			{
				for (var s1:String in childrenOfScene)
				{	
					for ( var i1:String in exceptional3dSpots )
					{
						if (s1 == exceptional3dSpots[i1] )
						{
							scene.removeChildByName(s1)
						}
					}
				}
			}
			else if ( whatToDoWith3dSpots == "deleteAll" )
			{	
				exceptional3dSpots.push(panoCubeReservedName);
				//trace(childrenOfScene, "|", scene.children, "|", exceptional3dSpots)
				for (var s2:String in childrenOfScene)
				{ 
					var isExceptional:Boolean = false;
					
					for ( var i2:String in exceptional3dSpots )
					{	
						if (s2 == exceptional3dSpots[i2] )
							isExceptional = true;
					}
					if (!isExceptional)
						scene.removeChildByName(s2); 
				}
			}
		}
		
		
		
		//converts spherical coords to cartesian
		private function pinToSphere(r:Number, p:Number, t:Number):Object
		{
			var pr:Number	= (-1*(p - 90)) * (Math.PI/180); 
			var tr:Number	= t * (Math.PI/180);
			var xc:Number = r * Math.cos(pr) * Math.cos(tr);
			var yc:Number = r * Math.sin(tr);
			var zc:Number = r * Math.sin(pr) * Math.cos(tr);
			
			var retObj:Object = { 
				x:xc, 
				y:yc,
				z:zc
				};
			return retObj;
		}
		
		
		private function navOver(event:Event):void
		{	
			TweenFilterLite.to( (event.target as DisplayObject), 0.5, {type:"Color", amount:1, saturation:0});
		}
		
		private function navOut(event:Event):void
		{	
			TweenFilterLite.to( (event.target as DisplayObject), 0.5, {type:"Color", amount:1, saturation:1});
			
		}
		private function buttonModeOn(event:Event):void
		{
			viewport.buttonMode = true;
		}
		private function buttonModeOff(event:Event):void
		{
			viewport.buttonMode = false;
		}
		
		private function hideClick(event:MouseEvent):void {

			TweenLite.to(navStrip, 0.25, { y:115, onComplete:onFinishTween } );
			navStrip.getChildByName("hideShowSprite").removeEventListener(MouseEvent.MOUSE_DOWN, hideClick, false);
			navStrip.getChildByName("hideShowSprite").addEventListener(MouseEvent.MOUSE_DOWN, hideFullscreenThenShowClick, false);
			hideShow.text = "Show Navigation"
		}
		
		private function onFinishTween():void {
		TweenLite.to(navStrip.getChildByName("buttonFullScreen"), 0.15, { y:"-100" } );
		}
		
		private function hideFullscreenThenShowClick(event:MouseEvent):void {
		TweenLite.to(navStrip.getChildByName("buttonFullScreen"), 0.15, { y:"100", onComplete:showClick  } );
		}		
		
		private function showClick():void
		{
			TweenLite.to(navStrip, 0.50, { y:0 } );
			navStrip.getChildByName("hideShowSprite").removeEventListener(MouseEvent.MOUSE_DOWN, hideFullscreenThenShowClick, false);
			navStrip.getChildByName("hideShowSprite").addEventListener(MouseEvent.MOUSE_DOWN, hideClick, false);
			hideShow.text = "Hide Navigation"
		}
		//
		private function hideOver(event:MouseEvent):void {
			var hideShowFormat:TextFormat = new TextFormat();
			hideShowFormat.color = 0xFFFF33;
			hideShow.setTextFormat(hideShowFormat);
		}
		private function hideOut(event:MouseEvent):void {
			var hideShowFormat:TextFormat = new TextFormat();
			hideShowFormat.color = 0xFFFFFF;
			hideShow.setTextFormat(hideShowFormat);
		}
		
		private function autorotationClick(event:MouseEvent):void
		{
			if (fc3d.isAutoRotating)
			{
				autorotationClickOff()
			}
			else{
				TweenLite.delayedCall(0.1, turnOnAutorotation);
			}
		}
		
		private function autorotationClickOn(event:MouseEvent=null):void
		{
			TweenLite.delayedCall(0.1, turnOnAutorotation);
		}
		
		private function turnOnAutorotation():void
		{
			fc3d.autoRotateNow();
		}
		
		private function autorotationClickOff(event:MouseEvent=null):void
		{
			fc3d.autoRotation = false;
		}
		
		private function zoomOutClick(event:MouseEvent):void
		{
			//TweenLite.to(camera, 1, {zoom:"-2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_DOWN )
			e.keyCode = Keyboard.CONTROL;
			viewport.stage.dispatchEvent( e );
		}
		private function zoomInClick(event:MouseEvent):void
		{	
			//TweenLite.to(camera, 1, {zoom:"+2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_DOWN )
			e.keyCode = Keyboard.SHIFT;
			viewport.stage.dispatchEvent( e );
		}
		private function panLeftClick(event:MouseEvent):void
		{	
			//TweenLite.to(fc3d, 0.5,{panVelocity:"-2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_DOWN )
			e.keyCode = Keyboard.LEFT;
			viewport.stage.dispatchEvent( e );
		}
		private function panRightClick(event:MouseEvent):void
		{
			//TweenLite.to(fc3d, 0.5,{panVelocity:"2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_DOWN )
			e.keyCode = Keyboard.RIGHT;
			viewport.stage.dispatchEvent( e );
		}
		private function tiltUpClick(event:MouseEvent):void
		{
			//TweenLite.to(fc3d, 0.5,{tiltVelocity:"2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_DOWN )
			e.keyCode = Keyboard.UP;
			viewport.stage.dispatchEvent( e );
		}
		private function tiltDownClick(event:MouseEvent):void
		{
			//TweenLite.to(fc3d, 0.5,{tiltVelocity:"-2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_DOWN )
			e.keyCode = Keyboard.DOWN;
			viewport.stage.dispatchEvent( e );
		}
		
		private function zoomOutRelease(event:MouseEvent):void
		{
			//TweenLite.to(camera, 1, {zoom:"-2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_UP )
			e.keyCode = Keyboard.CONTROL;
			viewport.stage.dispatchEvent( e );
		}
		private function zoomInRelease(event:MouseEvent):void
		{	
			//TweenLite.to(camera, 1, {zoom:"+2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_UP )
			e.keyCode = Keyboard.SHIFT;
			viewport.stage.dispatchEvent( e );
		}
		private function panLeftRelease(event:MouseEvent):void
		{	
			//TweenLite.to(fc3d, 0.5,{panVelocity:"-2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_UP )
			e.keyCode = Keyboard.LEFT;
			viewport.stage.dispatchEvent( e );
		}
		private function panRightRelease(event:MouseEvent):void
		{
			//TweenLite.to(fc3d, 0.5,{panVelocity:"2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_UP )
			e.keyCode = Keyboard.RIGHT;
			viewport.stage.dispatchEvent( e );
		}
		private function tiltUpRelease(event:MouseEvent):void
		{
			//TweenLite.to(fc3d, 0.5,{tiltVelocity:"2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_UP )
			e.keyCode = Keyboard.UP;
			viewport.stage.dispatchEvent( e );
		}
		private function tiltDownRelease(event:MouseEvent):void
		{
			//TweenLite.to(fc3d, 0.5,{tiltVelocity:"-2"} );
			var e:KeyboardEvent = new KeyboardEvent( KeyboardEvent.KEY_UP )
			e.keyCode = Keyboard.DOWN;
			viewport.stage.dispatchEvent( e );
		}
		
		private function buttonFullScreenClick(event:MouseEvent):void
		{
			switch(stage.displayState) 
			{
				case "normal":
					stage.displayState = "fullScreen";    
					break;
				case "fullScreen":
				default:
				stage.displayState = "normal";    
					break;
			}
			TweenLite.delayedCall(0.1, onResize);
		}
		
		///tooltip event handlers
		private function tooltipMove(event:MouseEvent = null):void
		{	
			tooltip.x = viewport.mouseX - tooltip.getChildAt(1).width/2 - 10;
			tooltip.y = viewport.mouseY - tooltip.getChildAt(1).height - 25;
		}
		private function tooltipOn(event:Event):void
		{	
			// set htmltext to the entry in tooltipTexts matching the name of the event target
			TextField(tooltip.getChildAt(1)).htmlText = tooltipTexts[event.target.name];
			//adjust background size to textfield
			Sprite(tooltip.getChildAt(0)).width = TextField(tooltip.getChildAt(1)).width+10;
			Sprite(tooltip.getChildAt(0)).height = TextField(tooltip.getChildAt(1)).height+25;
			tooltipMove();
			
			tooltip.alpha = 0;
			
			viewport.stage.addEventListener(MouseEvent.MOUSE_MOVE, tooltipMove, false, 0, true);
			
			addChild(tooltip);
			TweenLite.to( tooltip, 0.1, {autoAlpha:1} );
			//set tooltip to fade out after 2 seconds
			TweenLite.to( tooltip, 0.1, {autoAlpha:0, delay:2, overwrite:false, onComplete:function():void{ TextField(tooltip.getChildAt(1)).htmlText = tooltipTexts.none; removeTooltip();} } );
		}
		private function tooltipOff(event:Event):void
		{
			TweenLite.to( tooltip, 0.1, {autoAlpha:0, onComplete:function():void{ TextField(tooltip.getChildAt(1)).htmlText = tooltipTexts.none; removeTooltip();} } );
		}
		private var called:int = 0;
		private function removeTooltip():void
		{
			if ( this.contains(tooltip) )
				removeChild(tooltip);
			viewport.stage.removeEventListener( MouseEvent.MOUSE_MOVE, tooltipMove, false );
		}
		
		// function to layout slider content as it arrives.  Will be layed out in the order of the display list
		private function sliderContentItemLoaded(event:Event):void 
		{
			var distanceToThisThumb:Number = 0;
			
			for(var i:int=0; i<=sliderContent.numChildren-1; i++)
			{ 
				var currentThumb:Object = sliderContent.getChildAt(i);
				currentThumb.x = distanceToThisThumb + ( i * gap );
				var w:Number;
				try { w = currentThumb.width}
				catch(e:Error){ w = 0; }
				distanceToThisThumb += w;
			}
		}
		
		private function sliderLeftClick(event:MouseEvent):void
		{
			rect = sliderContent.scrollRect;
			var mostMarginalThumbX:Number = 0;
			
			for(var i:int=0; i<=sliderContent.numChildren-1; i++)
			{
				var currentThumb:Object = sliderContent.getChildAt(i);
				if ( currentThumb.x < rect.x )
				{
					mostMarginalThumbX = currentThumb.x;
					var w:Number;
					try { w = currentThumb.width}
					catch(e:Error){ w = 0; }
				}
			}
			
			var distance:int = (rect.x - rect.width < 0) ? -1 * rect.x : -1 * ((rect.x + rect.width) - mostMarginalThumbX - w );
			TweenLite.to( rect, 1, { x:String(distance), onUpdate:scrollSlider } );
			sliderContent.scrollRect = rect;
		}
		private function sliderRightClick(event:MouseEvent):void
		{
			rect = sliderContent.scrollRect; 
			var sliderWidth:Number = 0;
			var mostMarginalThumbX:Number = 9999;
			
			for(var i:int=0; i<=sliderContent.numChildren-1; i++)
			{ 
				var currentThumb:Object = sliderContent.getChildAt(i);
				var w:Number;
				try { w = currentThumb.width}
				catch(e:Error){ w = 0; }
				if ( currentThumb.x + w > sliderWidth )
				{
					sliderWidth = currentThumb.x + w;
				}
			}
			for(i=0; i<=sliderContent.numChildren-1; i++)
			{
				currentThumb = sliderContent.getChildAt(i);
				if ( currentThumb.x + w > rect.x + rect.width )
				{
					if ( currentThumb.x < mostMarginalThumbX )
					{
						mostMarginalThumbX = currentThumb.x;
					}
				}
			}
			var distance:int = (rect.x + rect.width + rect.width > sliderWidth) ? sliderWidth - rect.x - rect.width : mostMarginalThumbX - rect.x;
			TweenLite.to( rect, 1, { x:String(distance), onUpdate:scrollSlider } );
			sliderContent.scrollRect = rect;
		}
		private function scrollSlider():void
		{
			sliderContent.scrollRect = rect;
		}
		
		
		
		
		
		
		
		
		
		
		
// 		private function pinToSphere(rad:Number, theta:Number, phi:Number):Object
// 		{
// 			var cartesianCoords:Number3D = sphericalToCartesian(rad, theta, phi);
// 			var retObj:Object = { 
// 				x:cartesianCoords.x, 
// 				y:cartesianCoords.y,
// 				z:cartesianCoords.z
// 				};
// 				trace(rad, theta, phi, cartesianCoords.x, cartesianCoords.y, cartesianCoords.z);
// 			return retObj;
// 		}
// 		
// 		
// 		/**
// 		* Deterines the spherical Cartesian coordinates (x,y,z) from Spherical coordinates (radius, phi, theta).
// 		* http://mathworld.wolfram.com/SphericalCoordinates.html
// 		**/
// 		private function sphericalToCartesian (radius:Number, thetad:Number, phid:Number):Number3D
// 		{	
// 			// convert degrees to radians
// 			var theta:Number 	= thetad * (Math.PI/180); 
//  			var phi:Number	 	= phid * (Math.PI/180);
// 			var x:Number = radius * Math.cos(theta) * Math.sin(phi);
// 			var y:Number = radius * Math.sin(theta) * Math.sin(phi);
// 			var z:Number = radius * Math.cos(phi);
// 
// 			// my calculations tilt 90, -90 work, pan is off
// // 			var x:Number = radius * Math.cos(theta) * Math.cos(phi);
// // 			var y:Number = radius * Math.cos(theta) * Math.sin(phi);
// // 			var z:Number = radius * Math.sin(theta);
// 			
// 			return new Number3D(x, y, z);
// 		}
// 		
// 		/**
// 		* converts Cartesian coordinates to Spherical coordinates.
// 		* http://www.math.montana.edu/frankw/ccp/multiworld/multipleIVP/spherical/body.htm
// 		**/ 
// 		private function cartesianToSpherical (pos:Number3D):Object
// 		{
// 			var r:Number		 = Math.sqrt( pos.x*pos.x + pos.y*pos.y + pos.z*pos.z );
// 			var S:Number 		 = Math.sqrt( pos.x*pos.x + pos.y*pos.y );
// 			var phi:Number		 = Math.acos( pos.z/r );
// 			var theta:Number	 = (pos.x < 0) ? Math.PI - Math.asin( pos.y/S ) : Math.asin( pos.y/S );
// 			
// 			//convert radians to degrees
// 			theta = theta * 180/Math.PI;
// 			phi = phi * 180/Math.PI;
// 			return {r:r, theta:theta, phi:phi};
// 		}
// 		
// 		private function degreesToRadians (deg:Number):Number
// 		{
// 			var radians:Number = deg * Math.PI/180;
// 			return radians;
// 		}
// 		private function radiansToDegrees (rad:Number):Number
// 		{
// 			var degrees:Number = rad * 180/Math.PI;
// 			return degrees;
// 		}
		
		
		
		
	}
}
